﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
using System.Threading;
using BLToolkit.Data;
using BLToolkit.Data.DataProvider;
using BLToolkit.Data.Linq;
using BLToolkit.Data.Sql;
using BLToolkit.Data.Sql.SqlProvider;
using BLToolkit.DataAccess;
using BLToolkit.Mapping;
using BLToolkit.Validation;

//using CRootGUI.Common.Helpers;

namespace Clipping.Utils
{
	/// <summary>
	/// 数据库操作辅助文件
	/// </summary>
	public class DBHelper
	{
		/// <summary>
		/// ORM是否初始化
		/// 静态变量，整个进程只需要初始化一次
		/// </summary>
		internal static bool ORMInitialized = false;

		static DBHelper()
		{
			//初始化ORM
			InitializeORM();
		}

		/// <summary>
		/// 初始化ORM
		/// 因为第一次使用ORM时比较耗时，所以需要提前初始化
		/// </summary>
		private static void InitializeORM()
		{
			//只需要初始化一次
			if (!ORMInitialized)
			{
				ORMInitialized = true;

				ThreadPool.QueueUserWorkItem((WaitCallback)delegate
					{
					
							//创建一个临时数据库，用于初始化ORM的操作
							string dbpath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
							while (System.IO.File.Exists(dbpath))
								dbpath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());

							using (DBConnectionPool pool = new DBConnectionPool(DataProviderName.SQLite, string.Format("Data Source={0};Version=3;Journal Mode=Off;Synchronous=Off;", dbpath), 1))
							{
								//初始化/升级数据库
								using (DBConnection conn = pool.GetConnection())
								{
									//获取数据库版本信息
									int curVersion = GetDBVersion(conn);

									DBVERSION version = DBVERSION.Records.Where(x => x.NAME == "DB").FirstOrDefault();
								}
							}
						
					});
			}
		}

        /// <summary>
        /// 创建数据库连接池
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dbPath"></param>
        /// <param name="maxConnNum">因为Sqlite多线程并发存在问题，所以默认只允许一个连接对象</param>
        /// <param name="password"></param>
        /// <returns></returns>
        public static DBConnectionPool CreateDBConnectionPool<T>(string dbPath, int maxConnNum = 1, string password = null)
			where T : DBUpdater
		{
			
            if (string.IsNullOrEmpty(password))
                password = "06zSah3QyW8e";

			//获取绝对路径
			dbPath = Path.GetFullPath(dbPath);

			//如果路径(目录)不存在，则创建目录
			if (!Directory.Exists(Path.GetDirectoryName(dbPath)))
				Directory.CreateDirectory(Path.GetDirectoryName(dbPath));

			//打开/创建数据库连接
			DBConnectionPool pool = new DBConnectionPool(DataProviderName.SQLite, string.Format("Data Source={0};Version=3;Journal Mode=Off;Synchronous=Off;Password={1};", dbPath, password), maxConnNum);

			//初始化/升级数据库
			using (DBConnection conn = pool.GetConnection())
			{
				//获取数据库版本信息
				int curVersion = GetDBVersion(conn);

				//升级
				if (!typeof(T).IsAbstract)
				{
					DBUpdater dbu = Activator.CreateInstance(typeof(T)) as DBUpdater;
					dbu.UpdateDB(curVersion, conn);
				}
			}

			return pool;
		}

		/// <summary>
		/// 升级数据库中的表结构
		/// </summary>
		public static void UpdateTableSchema<T>(DBConnectionPool pool)
			where T : IDBUpdater
		{
			//初始化/升级数据库
			using (DBConnection conn = pool.GetConnection())
			{
				//获取数据库版本信息
				int curVersion = GetDBVersion(conn, typeof(T).Name);

				//升级
				if (!typeof(T).IsAbstract)
				{
					IDBUpdater dbu = Activator.CreateInstance(typeof(T)) as IDBUpdater;
					dbu.UpdateDB(curVersion, conn);
				}
			}
		}

		/// <summary>
		/// 初始化数据库版本信息
		/// </summary>
        /// <param name="conn"></param>
        /// <param name="name"></param>
		/// <returns>数据库版本信息</returns>
		static int GetDBVersion(DBConnection conn, string name = "Database")
		{
			if (conn == null) return -1;

			//确保DBVersion表存在
			conn.SetCommand(@"CREATE TABLE IF NOT EXISTS DBVersion(Name varchar(20) PRIMARY KEY, Version int);").ExecuteNonQuery();

			//获取当前的数据库版本
			int curVersion = -1;
			
			System.Data.IDataReader reader = conn.SetCommand("select count(*) count, max(VERSION) version from DBVERSION where Name == @Name",
				conn.Parameter("@Name", name)).ExecuteReader();

			if (reader != null && reader.Read())
			{
				int count = reader.GetInt32(0);
				if (count > 0)
					curVersion = reader.GetInt32(1);

				reader.Close();

				if (count <= 0)
					conn.SetCommand(string.Format("insert into DBVersion(Name,Version) values('{0}', -1)", name)).ExecuteNonQuery();
			}

			return curVersion;
		}
	}

	/// <summary>
	/// 数据库升级操作
	/// </summary>
	public class UpdateAction
	{
		/// <summary>
		/// 版本信息
		/// </summary>
		public int Version { get; set; }

		/// <summary>
		/// 升级操作对应的SQL语句
		/// </summary>
		public string UpdateSQL { get; set; }
	}

	/// <summary>
	/// 数据库版本控制表
	/// </summary>
	[TableName(Name = "DBVersion")]
	internal class DBVERSION : ModelBase<DBVERSION>
	{
		[PrimaryKey(0), Required]
		public string NAME { get; set; }
		[Required]
		public int VERSION { get; set; }
	}

	public interface IDBUpdater
	{
		void UpdateDB(int version, DBConnection conn);
	}

	/// <summary>
	/// 数据库中的部分表结构升级
	/// </summary>
	public abstract class DBPartUpdater<T> : IDBUpdater
	{
		protected static Dictionary<Type, List<UpdateAction>> Actions = new Dictionary<Type, List<UpdateAction>>();
		protected static Dictionary<Type, int> Versions = new Dictionary<Type, int>();

		/// <summary>
        /// 添加升级操作SQL语句
		/// </summary>
		/// <param name="type"></param>
		/// <param name="sql"></param>
		protected static void AddUpdateAction(Type type, string sql)
		{
			if (!Versions.ContainsKey(type)) Versions[type] = 0;
			if (!Actions.ContainsKey(type)) Actions[type] = new List<UpdateAction>();

			UpdateAction ua = new UpdateAction { Version = Versions[type]++, UpdateSQL = sql };
			Actions[type].Add(ua);
		}

		/// <summary>
		/// 当前数据库需要进行的升级操作
		/// </summary>
		List<UpdateAction> NeedUpdateActions;
		
		public DBPartUpdater()
		{
		}

		/// <summary>
        /// 升级操作
		/// </summary>
		/// <param name="version"></param>
		/// <param name="conn"></param>
		public void UpdateDB(int version, DBConnection conn)
		{
			NeedUpdateActions = new List<UpdateAction>(Actions[this.GetType()].Where(x => x.Version > version));

			if (conn == null || NeedUpdateActions.Count == 0) return;

			//启动事务
			conn.BeginTransaction();

			NeedUpdateActions.ForEach((x) =>
				{
					if (!string.IsNullOrEmpty(x.UpdateSQL))
					{
						//执行升级SQL
						conn.SetCommand(x.UpdateSQL).ExecuteNonQuery();

						//更新版本
						version = x.Version;
					}
				});

			//更新版本
			conn.SetCommand("update DBVersion set Version=@Version where Name=@Name", conn.Parameter("@Version", version), conn.Parameter("@Name", typeof(T).Name)).ExecuteNonQuery();

			//提交事务
			conn.CommitTransaction();
		}
	}

	/// <summary>
	/// 虚拟的整个数据库表
	/// </summary>
	public abstract class Database { }
	
	/// <summary>
	/// 数据库升级类
	/// </summary>
	public abstract class DBUpdater : DBPartUpdater<Database>
	{
	}
}
